package openmods.calc.types.multi; import java.math.BigInteger; import openmods.calc.parsing.IValueParser; import openmods.calc.parsing.PositionalNotationParser; import openmods.calc.parsing.Token; import openmods.calc.parsing.TokenType; import org.apache.commons.lang3.tuple.Pair; public class TypedValueParser implements IValueParser<TypedValue> { public static final PositionalNotationParser<BigInteger, Double> NUMBER_PARSER = new PositionalNotationParser<BigInteger, Double>() { @Override public Accumulator<BigInteger> createIntegerAccumulator(int radix) { final BigInteger bigRadix = BigInteger.valueOf(radix); return new Accumulator<BigInteger>() { private BigInteger value = BigInteger.ZERO; @Override public void add(int digit) { value = value.multiply(bigRadix).add(BigInteger.valueOf(digit)); } @Override public BigInteger get() { return value; } }; } @Override protected Accumulator<Double> createFractionalAccumulator(int radix) { final double inverseRadix = 1.0 / radix; return new Accumulator<Double>() { private double value = 0; private double weight = inverseRadix; @Override public void add(int digit) { value += digit * weight; weight *= inverseRadix; } @Override public Double get() { return value; } }; } }; public static TypedValue mergeNumberParts(TypeDomain domain, Pair<BigInteger, Double> result) { final BigInteger intPart = result.getLeft(); final Double fractionPart = result.getRight(); if (fractionPart == null) return domain.create(BigInteger.class, intPart); final double total = intPart.doubleValue() + fractionPart; return domain.create(Double.class, total); } private final TypeDomain domain; public TypedValueParser(TypeDomain domain) { this.domain = domain; } @Override public TypedValue parseToken(Token token) { if (token.type == TokenType.STRING) return domain.create(String.class, token.value); final Pair<BigInteger, Double> result = NUMBER_PARSER.parseToken(token); return mergeNumberParts(domain, result); } }